home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / DETH_SRC.ZIP / SOUND.C < prev    next >
Text File  |  1993-06-27  |  17KB  |  902 lines

  1.  
  2. /* Copyright 1993 by Peter Sprenger   Pete@amber.dinoco.de
  3.  *                   5014 Kerpen 3
  4.  *                   Germany
  5.  *
  6.  * Permission to use, copy, modify, and distribute this
  7.  * software and its documentation for any purpose and without
  8.  * fee is hereby granted, provided that the above copyright
  9.  * notice appear in all copies.  The author Peter Sprenger
  10.  * makes no representations about the suitability of this
  11.  * software for any purpose.  It is provided "as is" without
  12.  * express or implied warranty.
  13.  */
  14.  
  15.  
  16. #include <stddef.h>
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <dos.h>
  20. #include <io.h>
  21. #include <fcntl.h>
  22. #include <alloc.h>
  23. #include <sys\stat.h>
  24. #include "mydef.h"
  25. #include "sound.h"
  26. #include "timerx.h"
  27. #include "dmalib.h"
  28.  
  29. static WORD ioaddr[6]={0x220,0x240,0x210,0x230,0x250,0x260};
  30. static WORD FM_off[9]={0,0x100,0x200,0x800,0x900,0xa00,0x1000,0x1100,0x1200};
  31. static BYTE FM_fnr[12]={0x57,0x6b,0x81,0x98,0xb0,0xca,0xe5,0x02,0x20,0x41,0x63,0x87};
  32. static BYTE FM_key_or[12]={1,1,1,1,1,1,1,2,2,2,2,2};
  33. static BYTE intrx[5]={7,5,2,3,10};
  34. static BYTE FM_key[9],FM_vol[9];
  35.  
  36. WORD io_addr,intnr,dma_ch,card_id,fm_addr,fm_left,fm_right,fm_both;
  37. static WORD mue3,mue23,dsp_vers,wh_card,rythm,rx,ry,midi_buflen;
  38. static WORD voccnt,cnt;
  39.  
  40. static BYTE DSP_intr_mode,DSP_high_mode,midi_mode,far *midi_recv;
  41. volatile BYTE voc_mode,tst_cnt,dma_sb_busy;
  42. static BYTE huge *vocptr,huge *vocrem,voc_ext,voc_pmode;
  43. static DWORD voc_blklen;
  44.  
  45. static void far interrupt (*orgint)();
  46.  
  47.  
  48. /*  ---------------  FM  Stuff ------------ */
  49.  
  50.  
  51. void FM_Write(WORD data)
  52. {
  53.     asm mov dx,fm_addr;
  54.     asm mov ax,data;
  55.  
  56.     asm xchg al,ah;
  57.     asm out dx,al;
  58.  
  59.     asm mov cx,mue3;
  60. loop1:
  61.     asm loop loop1;
  62.  
  63.     asm inc dx;
  64.     asm mov al,ah;
  65.     asm out dx,al;
  66.  
  67.     mdelay(mue23);
  68. }
  69.  
  70. void FM_Reset()
  71. {
  72.     FM_SetChan(both);
  73.     FM_Write(0x0120);
  74.     FM_Write(0x0800);
  75.     FM_Write(0xbdc0);
  76. }
  77.  
  78. BYTE FM_Status()
  79. {
  80.     asm mov dx,fm_addr;
  81.     asm in al,dx;
  82.     return(_AL);
  83. }
  84.  
  85. static int FM_Detect()
  86. {
  87.     int i;
  88.  
  89.     FM_Write(0x0100); /* init Test register */
  90.  
  91.     FM_Write(0x0460); /* reset both timer */
  92.     FM_Write(0x0480); /* enable interrupts */
  93.     if(FM_Status() & 0xe0) return(FALSE);
  94.  
  95.     FM_Write(0x02ff); /* write ffh to timer 1 */
  96.     FM_Write(0x0421); /* start timer 1 */
  97.     if(fm_addr==0x388) msdelay(21); /* wait 21000 mcs */
  98.     else mdelay(mcalc(80));   /* wait at least 80 microsec */
  99.     if((FM_Status() & 0xe0)!=0xc0) return(FALSE);
  100.  
  101.     FM_Write(0x0460); /* reset both timer */
  102.     FM_Write(0x0480); /* enable interrupts */
  103.     return(TRUE);
  104. }
  105.  
  106. void FM_SetChan(fm_chan channel)
  107. {
  108.     if(channel!=sbpro) return;
  109.     switch(channel)
  110.     {
  111.         case both:
  112.                    fm_addr=fm_both;
  113.                  break;
  114.         case left:
  115.                    fm_addr=fm_left;
  116.                  break;
  117.         case right:
  118.                    fm_addr=fm_right;
  119.     }
  120. }
  121.  
  122. void FM_SetVoice(BYTE voice,BYTE *ins)
  123. {
  124.     BYTE *insptr;
  125.     WORD data;
  126.     int i;
  127.  
  128.     insptr=ins;
  129.  
  130.     FM_vol[voice]=insptr[3];
  131.     data=0x2000+FM_off[voice];
  132.  
  133.     for(i=0;i<5;i++)
  134.     {
  135.         data=data&0xff00| *insptr++;
  136.         FM_Write(data);
  137.         data+=0x300;
  138.         data=data&0xff00| *insptr++;
  139.         FM_Write(data);
  140.         data=data+(0x2000-0x300);
  141.         if(i==3) data+=4000;
  142.     }
  143.     data=0xc000+(voice<<8);
  144.     data=data&0xff00| *insptr;
  145.     FM_Write(data);
  146. }
  147.  
  148. void FM_SetNote(BYTE voice,BYTE note)
  149. {
  150.     BYTE blk,notex;
  151.     WORD data;
  152.  
  153.     notex=note-24;
  154.     blk=1;
  155.     while(notex>=12)
  156.     {
  157.         notex-=12;
  158.         blk++;
  159.     }
  160.     data=0xa000+(voice<<8)|FM_fnr[notex];
  161.     FM_key[voice]=FM_key_or[notex]|(blk<<2);
  162.     FM_Write(data);
  163. }
  164.  
  165. void FM_SetVol(BYTE voice,BYTE vol)
  166. {
  167.    FM_Write(0x4320+FM_off[voice]-(((BYTE)vol&0x7f)>>2)|FM_vol[voice]);
  168. }
  169.  
  170. void FM_RythmMode(BYTE bool)
  171. {
  172.     WORD data;
  173.  
  174.     if(bool) data=0xbde0;
  175.     else data=0xbdc0;
  176.     rythm=data;
  177.     FM_Write(data);
  178. }
  179.  
  180. void FM_RythmOn(BYTE inst)
  181. {
  182.     rythm|=inst;
  183.     FM_Write(rythm);
  184. }
  185.  
  186. void FM_RythmOff(BYTE inst)
  187. {
  188.     rythm&=(~inst);
  189.     FM_Write(rythm);
  190. }
  191.  
  192. void FM_KeyOn(BYTE voice)
  193. {
  194.     WORD data;
  195.  
  196.     data=0xb000+(voice<<8)|FM_key[voice]|0x20;
  197.     FM_Write(data);
  198. }
  199.  
  200. void FM_KeyOff(BYTE voice)
  201. {
  202.     WORD data;
  203.  
  204.     data=0xb000+(voice<<8)|FM_key[voice];
  205.     FM_Write(data);
  206. }
  207.  
  208.  
  209.  
  210.  
  211.  
  212. /*  ---------------  Mixer  Stuff ------------ */
  213.  
  214.  
  215. void MIX_Reset()
  216. {
  217.     asm mov dx,io_addr
  218.     asm add dx,MIX_ADR_OFF
  219.     asm mov al,0
  220.     asm out dx,al
  221.     asm inc dx
  222.     asm out dx,al
  223. }
  224.  
  225. void MIX_SetInput(BYTE opt)
  226. {
  227.     asm mov dx,io_addr;
  228.     asm add dx,MIX_ADR_OFF;
  229.     asm mov al,MIX_INPUT;
  230.     asm out dx,al;
  231.     asm inc dx;
  232.     asm mov al,opt;
  233.     asm out dx,al;
  234. }
  235.  
  236. void MIX_SetOutput(BYTE opt)
  237. {
  238.     asm mov dx,io_addr;
  239.     asm add dx,MIX_ADR_OFF;
  240.     asm mov al,MIX_OUTPUT;
  241.     asm out dx,al;
  242.     asm inc dx;
  243.     asm mov al,opt;
  244.     asm out dx,al;
  245. }
  246.  
  247. void MIX_SetVolume(BYTE reg,BYTE left,BYTE right)
  248. {
  249.     asm mov dx,io_addr
  250.     asm add dx,MIX_ADR_OFF
  251.     asm mov al,reg
  252.     asm out dx,al
  253.     asm inc dx
  254.     asm mov al,left
  255.     asm mov cl,4
  256.     asm shl al,cl
  257.     asm or al,right
  258.     asm out dx,al
  259. }
  260.  
  261. void MIX_GetVolume(BYTE reg,BYTE *left,BYTE *right)
  262. {
  263.     asm mov dx,io_addr
  264.     asm add dx,MIX_ADR_OFF
  265.     asm mov al,reg
  266.     asm out dx,al
  267.     asm inc dx
  268.     asm in al,dx
  269.     asm mov ah,al
  270.     asm les bx,right
  271.     asm and al,0xf
  272.     asm mov es:[bx],al
  273.     asm mov al,ah
  274.     asm les bx,left
  275.     asm mov cl,4
  276.     asm shr al,cl
  277.     asm mov es:[bx],al
  278. }
  279.  
  280.  
  281.  
  282. /*  ---------------  Midi  Stuff ------------ */
  283.  
  284.  
  285.  
  286. void MIDI_Write(BYTE data)
  287. {
  288.     DSP_Write(DSP_MIDI_WRITE);
  289.     DSP_Write(data);
  290. }
  291.  
  292. void MIDI_WriteBuf(BYTE *data,int length)
  293. {
  294.     int i;
  295.  
  296.     for(i=0;i<length;i++) MIDI_Write(data[i]);
  297. }
  298.  
  299. static void far interrupt midi_int()
  300. {
  301.     asm mov dx,io_addr;   /* read midi code from DSP */
  302.     asm add dx,DSP_READ;
  303.     asm in al,dx;
  304.  
  305.     asm mov si,rx;        /* write code into buffer */
  306.     asm inc si;
  307.     asm cmp si,midi_buflen; /* make turnaround at buffer limit */
  308.     asm jnz no_turn
  309.     asm mov si,0
  310. no_turn:
  311.     asm mov rx,si;
  312.     asm les bx,midi_recv;
  313.     asm mov es:[bx][si],al
  314.  
  315.     asm mov dx,io_addr;
  316.     asm add dx,DSP_RSTATUS;
  317.     asm in al,dx;         /* Ack DSP interrupt */
  318.  
  319.     asm mov al,0x20;
  320.     asm out 0x20,al; /* set EOI to master */
  321.     asm mov bx,intnr
  322.     asm cmp bx,7
  323.     asm jbe end
  324.     asm out 0xa0,al; /* set EOI to slave */
  325.  
  326. end:
  327. }
  328.  
  329. WORD  MIDI_ByteAvail()
  330. {
  331.     if(ry<rx) return(midi_buflen-rx+ry);
  332.     else return(ry-rx);
  333. }
  334.  
  335. BYTE MIDI_GetByte()
  336. {
  337.     if(++ry==midi_buflen) ry=0;
  338.     return(midi_recv[ry]);
  339. }
  340.  
  341. void MIDI_ReadBuf(WORD count,BYTE *buffer)
  342. {
  343.     int i;
  344.  
  345.     for(i=0;i<count;i++)
  346.     {
  347.         if(++ry==midi_buflen) ry=0;
  348.         buffer[i]=midi_recv[ry];
  349.     }
  350.     /* not the fastest! this routine has to be improved in the future */
  351. }
  352.  
  353. int MIDI_Init(BYTE mode,WORD buflen)
  354. {
  355.     midi_mode=mode;
  356.     if(mode==DSP_MIDI_UART && dsp_vers<0x2000) return(FALSE);
  357.     midi_recv=malloc(buflen);
  358.     if(!midi_recv) return(FALSE);
  359.     midi_buflen=buflen;
  360.     rx=ry=0;
  361.     DSP_Write(mode);
  362.     return(TRUE);
  363. }
  364.  
  365. void MIDI_Remove()
  366. {
  367.     if(midi_mode==DSP_MIDI_READI) DSP_Write(DSP_MIDI_READI);
  368.     else DSP_Reset();
  369.     if(midi_recv) free(midi_recv);
  370. }
  371.  
  372.  
  373.  
  374. /*  ---------------  voc  Stuff ------------ */
  375.  
  376.  
  377.  
  378. int VocPlay(char far *data)
  379. {
  380.     vocptr=data;
  381.     if(strncmp(vocptr,"Creative Voice File\x1a",20) || *((WORD *)vocptr+11)!=(~*((WORD *)vocptr+12)+0x1234))
  382.         return(FALSE);
  383.     vocptr+=*((WORD *)vocptr+10);
  384.     voc_mode=TRUE;
  385.     voc_ext=FALSE;
  386.     voccnt=0;
  387.     VocHandle();
  388.     return(TRUE);
  389. }
  390.  
  391. void VocStop()
  392. {
  393.     voc_mode=FALSE;
  394.     if(dma_sb_busy) DSP_Write(DSP_HALT_DMA);
  395. }
  396.  
  397. static void VocHandle()
  398. {
  399.     BYTE tmp;
  400.  
  401.     while(*vocptr)
  402.     {
  403.         voc_blklen=((DWORD)(*(vocptr+3))<<16)+ *((WORD *)(vocptr+1))+4;
  404.         switch(*vocptr)
  405.         {
  406.             case 1:    if(!voc_ext)
  407.                     {
  408.                         DSP_Write(DSP_SAMPLE_RATE);
  409.                         DSP_Write(*(vocptr+4));
  410.                         voc_pmode=*(vocptr+5);
  411.                     }
  412.                     else
  413.                     voc_ext=FALSE;
  414.                     Play((char far *)vocptr+6,voc_pmode,voc_blklen-6);
  415.                     vocptr+=voc_blklen;
  416.                     return;
  417.             case 2: Play((char far *)vocptr+4,voc_pmode,voc_blklen-4);
  418.                     vocptr+=voc_blklen;
  419.                     return;
  420.             case 3: DSP_Write(DSP_SAMPLE_RATE);
  421.                     DSP_Write(*(vocptr+6));
  422.                     DSP_Write(DSP_SILENCE);
  423.                     DSP_Write(*(vocptr+4));
  424.                     DSP_Write(*(vocptr+5));
  425.                     vocptr+=7;
  426.                     return;
  427.             case 6: vocrem=vocptr+6;
  428.                     voccnt=*((WORD *)(vocptr+4));
  429.                     vocptr+=6;
  430.                    break;
  431.             case 7: if(voccnt) vocptr=vocrem;
  432.                     if(voccnt!=0xffff) voccnt--;
  433.                    break;
  434.             case 8: DSP_Write(DSP_SAMPLE_RATE);
  435.                     DSP_Write(*(vocptr+5));
  436.                     if(*(vocptr+7)) tmp=MIX_STEREO;
  437.                     else tmp=MIX_MONO;
  438.                     MIX_SetOutput(tmp);
  439.                     voc_pmode=*(vocptr+6);
  440.                     voc_ext=TRUE;
  441.                     vocptr+=8;
  442.                    break;
  443.         }
  444.     }
  445.     voc_mode=FALSE;
  446. }
  447.  
  448.  
  449.  
  450.  
  451. /*  ---------------  DSP  Stuff ------------ */
  452.  
  453.  
  454.  
  455. int DSP_Reset()
  456. {
  457.     int i;
  458.  
  459.     asm mov dx,io_addr;
  460.     asm add dx,DSP_RESET;
  461.     asm mov al,1
  462.     asm out dx,al;
  463.  
  464.     mcalc(mue3);
  465.  
  466.     asm mov dx,io_addr;
  467.     asm add dx,DSP_RESET;
  468.     asm mov al,0
  469.     asm out dx,al;
  470.  
  471.     for(i=0;i<50;i++)
  472.     {
  473.         mcalc(mue3);
  474.         if(DSP_Read()==0xaa) return(TRUE);
  475.     }
  476.  
  477.     return(FALSE);
  478. }
  479.  
  480. BYTE DSP_Read()
  481. {
  482.     asm mov dx,io_addr;
  483.     asm add dx,DSP_RSTATUS;
  484. loop:
  485.     asm in al,dx;
  486.     asm test al,0x80;
  487.     asm jz loop
  488.  
  489.     asm mov dx,io_addr;
  490.     asm add dx,DSP_READ;
  491.     asm in al,dx;
  492.     return(_AL);
  493. }
  494.  
  495. void DSP_Write(BYTE output)
  496. {
  497.     asm mov dx,io_addr;
  498.     asm add dx,DSP_WSTATUS;
  499. loop:
  500.     asm in al,dx;
  501.     asm test al,0x80;
  502.     asm jnz loop
  503.  
  504.     asm mov dx,io_addr;
  505.     asm add dx,DSP_WRITE;
  506.     asm mov al,output
  507.     asm out dx,al;
  508. }
  509.  
  510. int get_sb_env()
  511. {
  512.     char *str;
  513.     int ret;
  514.  
  515.     str=getenv("BLASTER");
  516.     if(!str) return(FALSE);
  517.     ret=sscanf(str,"A%x I%d D%d T%d",&io_addr,&intnr,&dma_ch,&card_id);
  518.     if(ret!=4 || io_addr<0x210 || io_addr>0x260 || dma_ch!=1 || intnr<2 || intnr>10)
  519.         return(FALSE);
  520.     return(TRUE);
  521. }
  522.  
  523. void SetRate(DWORD rate)
  524. {
  525.     DWORD val;
  526.  
  527.     if(rate<4000) return;
  528.     val=256-1000000/rate;
  529.     DSP_Write(DSP_SAMPLE_RATE);
  530.     DSP_Write((BYTE)val);
  531. }
  532.  
  533. void SetHighRate(DWORD rate)
  534. {
  535.     WORD val;
  536.  
  537.     if(rate<4000) return;
  538.     val=65536-(WORD)(256000000/rate);
  539.     DSP_Write(DSP_SAMPLE_RATE);
  540.     DSP_Write((BYTE)(val>>8));
  541. }
  542.  
  543. WORD DSP_GetVersion()
  544. {
  545.     DSP_Write(DSP_GET_VERS);
  546.     return((WORD)DSP_Read()*256+DSP_Read());
  547. }
  548.  
  549. int Play(char far *data,playmode mode,DWORD length)
  550. {
  551.     return(PlayXMS(far2long(data),mode,length));
  552. }
  553.  
  554. int PlayXMS(DWORD data,playmode mode,DWORD length)
  555. {
  556.     WORD len;
  557.     BYTE dsp_mode;
  558.  
  559.     if(dma_sb_busy)
  560.     {
  561.         DSP_Write(DSP_HALT_DMA);  /* halt dma */
  562.         dma_sb_busy=FALSE;
  563.     }
  564.     len=dma_set(data,length,dma_ch,DMA_OUT|DMA_SINGLE|DMA_AUTO)-1; /* set dma */
  565.  
  566.     DSP_high_mode=0;
  567.     switch(mode)
  568.     {
  569.         case bit8:
  570.                 dsp_mode=DSP_DMA_8BIT;
  571.                 DSP_intr_mode=DSP_DMA_8BIT;
  572.                break;
  573.         case bit4:
  574.                 dsp_mode=DSP_DMA_4BIT_REF;
  575.                 DSP_intr_mode=DSP_DMA_4BIT;
  576.                break;
  577.         case bit26:
  578.                 dsp_mode=DSP_DMA_26BIT_REF;
  579.                 DSP_intr_mode=DSP_DMA_26BIT;
  580.                break;
  581.         case bit2:
  582.                 dsp_mode=DSP_DMA_2BIT_REF;
  583.                 DSP_intr_mode=DSP_DMA_2BIT;
  584.                break;
  585.         case high:
  586.                 dsp_mode=DSP_BLOCK_SIZE;
  587.                 DSP_intr_mode=DSP_BLOCK_SIZE;
  588.                 DSP_high_mode=DSP_DMA_HIGHSPEED;
  589.     }
  590.     dma_sb_busy=TRUE;
  591.     DSP_Write(dsp_mode);
  592.     DSP_Write((BYTE)len);   /* write length to DSP */
  593.     DSP_Write((BYTE)(len>>8));
  594.     if(DSP_high_mode) DSP_Write(DSP_DMA_HIGHSPEED);
  595.  
  596.     return(TRUE);
  597. }
  598.  
  599. int Sample(char far *data,playmode mode,DWORD length)
  600. {
  601.     WORD len;
  602.     BYTE dsp_mode;
  603.  
  604.     if(dma_sb_busy)
  605.     {
  606.         DSP_Write(DSP_HALT_DMA);  /* halt dma */
  607.         dma_sb_busy=FALSE;
  608.     }
  609.     len=dma_set(far2long(data),length,dma_ch,DMA_IN|DMA_SINGLE|DMA_AUTO)-1; /* set dma */
  610.  
  611.     DSP_high_mode=0;
  612.     switch(mode)
  613.     {
  614.         case bit8:
  615.                 dsp_mode=DSP_DMA_ADC;
  616.                 DSP_intr_mode=DSP_DMA_ADC;
  617.                break;
  618.         case high:
  619.                 dsp_mode=DSP_BLOCK_SIZE;
  620.                 DSP_intr_mode=DSP_BLOCK_SIZE;
  621.                 DSP_high_mode=DSP_DMA_ADC_HIGHSPEED;
  622.     }
  623.     dma_sb_busy=TRUE;
  624.     DSP_Write(dsp_mode);
  625.     DSP_Write((BYTE)len);   /* write length to DSP */
  626.     DSP_Write((BYTE)(len>>8));
  627.     if(DSP_high_mode) DSP_Write(DSP_DMA_ADC_HIGHSPEED);
  628.  
  629.     return(TRUE);
  630. }
  631.  
  632.  
  633. static void far interrupt sb_int()
  634. {
  635.     WORD length;
  636.  
  637.     asm mov dx,io_addr;
  638.     asm add dx,DSP_RSTATUS;
  639.     asm in al,dx;         /* Ack DSP interrupt */
  640.  
  641.     if(dma_len(dma_ch))                /* if bytes left reprogram DSP */
  642.     {
  643.         length=dma_next(dma_ch)-1;  /* check for another dma block */
  644.         DSP_Write(DSP_intr_mode);   /* set DSP mode */
  645.         DSP_Write((BYTE)length);
  646.         DSP_Write((BYTE)(length>>8));
  647.         if(DSP_high_mode) DSP_Write(DSP_high_mode);
  648.     }
  649.     else
  650.     {
  651.         dma_sb_busy=FALSE;
  652.         if(voc_mode) VocHandle();
  653.     }
  654.  
  655.     asm mov al,0x20;
  656.     asm out 0x20,al; /* set EOI */
  657.     asm mov bx,intnr
  658.     asm cmp bx,7
  659.     asm jbe end
  660.     asm out 0xa0,al; /* set EOI */
  661.  
  662. end:
  663. }
  664.  
  665.  
  666.  
  667. /*  ---------------  Misc.  Stuff ------------ */
  668.  
  669.  
  670. int CardCheck()
  671. {
  672.     int ret=0;
  673.  
  674.     if(FM_Detect()) ret|=FM_DETECT;
  675.     if(DSP_Reset()) ret|=DSP_DETECT;
  676.     return(ret);
  677. }
  678.  
  679. static void far interrupt testn_int()
  680. {
  681.     tst_cnt++;
  682.  
  683.     asm mov dx,io_addr;
  684.     asm add dx,DSP_RSTATUS;
  685.     asm in al,dx;         /* Ack DSP interrupt */
  686.  
  687.     asm mov al,0x20;
  688.     asm out 0x20,al; /* set EOI */
  689.     asm mov bx,intnr
  690.     asm cmp bx,7
  691.     asm jbe end
  692.     asm out 0xa0,al; /* set EOI */
  693.  
  694. end:
  695. }
  696.  
  697. static BYTE scan_dma()
  698. {
  699.     BYTE dma1,dma2,dma1r,dma2r,cnt;
  700.  
  701.     DSP_Write(DSP_SPKR_OFF);
  702.     SetRate(22000);
  703.     DSP_Write(DSP_DMA_8BIT);
  704.     DSP_Write(10);
  705.  
  706.     asm cli
  707.  
  708.     asm in al,8
  709.     asm and al,0xe0
  710.     asm mov dma1,al
  711.     asm in al,0xd0
  712.     asm and al,0xf0
  713.     asm mov dma2,al
  714.  
  715.     DSP_Write(0);
  716.  
  717.     asm mov cx,60000
  718. loop1:
  719.     asm in al,8
  720.     asm and al,0xe0
  721.     asm mov dma1r,al
  722.     asm cmp al,dma1
  723.     asm jnz req
  724.  
  725.     asm in al,0xd0
  726.     asm and al,0xf0
  727.     asm mov dma2r,al
  728.     asm cmp al,dma2
  729.     asm jnz req
  730.  
  731.     asm loop loop1
  732. req:
  733.     asm sti
  734.     DSP_Reset(); /* cause our DSP it's a little bit confused */
  735.  
  736.     if(dma1!=dma1r)
  737.     {
  738.         cnt=0;
  739.         dma1r=dma1r&(~dma1);
  740.         while(dma1r>>=1) cnt++;
  741.         return(cnt-4);
  742.     }
  743.     if(dma2!=dma2r)
  744.     {
  745.         cnt=0;
  746.         dma2r=dma2r&(~dma2);
  747.         while(dma2r>>=1) cnt++;
  748.         return(cnt-4);
  749.     }
  750.     return(0xff);  /* no dma request occured ???? */
  751. }
  752.  
  753. static int test_int()
  754. {
  755.     int i;
  756.     BYTE int1,int2;
  757.  
  758.     tst_cnt=0;
  759.     orgint=getvect(int2vect(intnr));
  760.  
  761.     asm in al,0x21;   /* save org master intr settings */
  762.     asm mov int1,al;
  763.  
  764.     asm in al,0xa1;   /* save org slave intr settings */
  765.     asm mov int2,al;
  766.  
  767.     asm mov al,0xfe;
  768.     asm cli;
  769.     asm out 0x21,al;  /* disable ALL intr */
  770.     asm mov al,0xff
  771.     asm out 0xa1,al;
  772.     asm sti;
  773.  
  774.     enable_int(intnr);
  775.     setvect(int2vect(intnr),testn_int);
  776.  
  777.     DSP_Write(DSP_INVOKE_INTR);  /* still magic -- make DSP interrupt? */
  778.  
  779.     for(i=0;i<30000;i++) if(tst_cnt) break;
  780.  
  781.     asm cli;
  782.     asm mov al,int1;
  783.     asm out 0x21,al;  /* restore org master intr */
  784.  
  785.     asm mov al,int2;  /* restore org slave intr */
  786.     asm out 0xa1,al;
  787.     asm sti;
  788.     setvect(int2vect(intnr),orgint);
  789.  
  790.     if(i==30000) return(FALSE);
  791.     else return(TRUE);
  792. }
  793.  
  794. static int scan_int()
  795. {
  796.     int i;
  797.  
  798.     if(test_int()) return(intnr);
  799.     for(i=0;i<5;i++)
  800.     {
  801.         intnr=intrx[i];
  802.         if(test_int()) return(i);
  803.     }
  804.     return(0);
  805. }
  806.  
  807. static cardtype CheckHard()
  808. {
  809.     int ret,ret2,ret3;
  810.  
  811.     ret=DSP_Reset();
  812.     if(ret)
  813.     {
  814.         if(!scan_int()) return(none);
  815.  
  816.         fm_addr=io_addr+FM_BOTH_OFF;
  817.         if(!FM_Detect()) return(none); /* no fm? -> damaged! */
  818.  
  819.         fm_both=fm_addr;
  820.         fm_addr=io_addr+FM_RIGHT_OFF;
  821.         fm_right=fm_addr;
  822.         ret3=FM_Detect();
  823.         fm_addr=fm_both;
  824.  
  825.         if(ret3)
  826.         {
  827.             wh_card=sbpro;
  828.             fm_left=io_addr+FM_LEFT_OFF;
  829.         }
  830.         else wh_card=sb20;
  831.         return(wh_card);
  832.     }
  833.     return(nodsp);
  834. }
  835.  
  836. cardtype WhichCard()
  837. {
  838.     cardtype cret;
  839.     int i;
  840.  
  841.     if(get_sb_env()) cret=CheckHard();
  842.     if(cret!=nodsp) return(cret);
  843.  
  844.     intnr=7;
  845.     for(i=0;i<6;i++)
  846.     {
  847.         io_addr=ioaddr[i];
  848.  
  849.         cret=CheckHard();
  850.         if(cret!=nodsp) return(cret);
  851.     }
  852.  
  853.     fm_addr=0x388;
  854.     if(FM_Detect())
  855.     {
  856.         fm_both=fm_addr;
  857.         wh_card=adlib;
  858.         return(adlib);
  859.     }
  860.  
  861.     return(none);
  862. }
  863.  
  864. int SB_Setup()
  865. {
  866.     int ret,ret2;
  867.  
  868.     InitT2();  /* init Timer 2 */
  869.     measure(); /* time loop factor */
  870.     mue3=mcalc(3);   /* calc val for 3 micro sec delay */
  871.     mue23=mcalc(23);   /* calc val for 23 micro sec delay */
  872.  
  873.     dma_sb_busy=FALSE;
  874.     voc_mode=FALSE;
  875.     WhichCard();
  876.     if(wh_card==none) return(FALSE);
  877.     if(wh_card==sb20 || wh_card==sbpro)
  878.     {
  879.         dma_ch=scan_dma();
  880.         if(dma_ch==0xff) return(FALSE);
  881.         dsp_vers=DSP_GetVersion();
  882.         DSP_Write(DSP_SPKR_ON);
  883.     }
  884.     return(TRUE);
  885. }
  886.  
  887.  
  888. void SB_SetVect(vect which)
  889. {
  890.     orgint=getvect(int2vect(intnr));
  891.     if(which==midi) setvect(int2vect(intnr),midi_int);
  892.     setvect(int2vect(intnr),sb_int); /* set vector to our routine */
  893.     enable_int(intnr);       /* enable sb interrupt */
  894. }
  895.  
  896. void SB_RemoveVect()
  897. {
  898.     disable_int(intnr);   /* disable sb interrupt */
  899.     setvect(int2vect(intnr),orgint);    /* restore org intr vector */
  900. }
  901.  
  902.